《RE for Beginners》笔记

Code Patterns

The method

Exercises

写一些C语言小程序,然后用汇编重写,不断缩小代码大小。无实际意义,因最新的编译器优化效率很高,但能深入理解汇编和程序。

Optimization levels and debug information

典型的编译器有三种优化水平,0代表不优化

编译器还会产生一些debug信息在结果文件中

Some basics

A short introduction to the CPU

  • ISA instruction set architecture

X86 ISA是可变长指令,所以随着64位处理器产生指令变化很少。

ARM ISA是定长指令,定长的优点是可以方便的计算下一个指令地址

  • 4 bytes的ARM mode,2 bytes的Thumb mode,Thumb不能够满足部分4 bytes指令,产生了Thumb-2在Thumb基础上扩展了指令,支持新的4 bytes的指令,随后又出现了ARM-64使用固定长度4bytes。
  • ARM 、Thumb(Thumb-2)、ARM64属于不同的指令架构,一个指令集并非另一个的变种。
  • GPR General Purpose Registers(X86=16,ARM=16)

Numeral Systems

decimal numbers d结尾

binary numbers 0b开头或b结尾

hexadecimal numbers 0x开头或h结尾

octal numbers 0开头

整除问题的巧用

类比十进制数后0的个数,可以被相应10的倍数整除

二级制数或八进制或十六进制类比,如PE文件中地址十六进制表示0x41000、0x10001000,可以被0x1000(4096)整除,因为PE section被划分为4096 bytes块大小。

An Empty Function

1
2
3
4
void f()
{
return;
};

X86:

1
2
f:
ret

Returning Values

1
2
3
4
int f()
{
return 123;
};

X86:

1
2
3
f:
mov eax, 123
ret

Hello, world!

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}

X86:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CONST SEGMENT
$SG3830 DB 'hello, world', 0AH, 00H
CONST ENDS
PUBLIC _main
EXTRN _printf:PROC
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
push ebp
mov ebp, esp
push OFFSET $SG3830
call _printf
add esp, 4 // 32bit程序地址为4 bytes,部分使用 POP ECX,好处是命令长度从 3
// bytes缩短为1 bytes,且不改变flag寄存器值。
xor eax, eax // 用2 bytes命令来代替5 bytes的MOV EAX,0,一些也用SUB EAX,EAX来产生0。
pop ebp
ret 0
_main ENDP
_TEXT ENDS

IDA:

1
2
3
4
5
6
7
8
9
10
11
12
13
main proc near
var_10 = dword ptr -10h
push ebp
mov ebp, esp
and esp, 0FFFFFFF0h
sub esp, 10h
mov eax, offset aHelloWorld ; "hello, world\n"
mov [esp+10h+var_10], eax
call _printf
mov eax, 0
leave
retn
main endp

5行and esp, 0FFFFFFF0h这条指令该指令对齐在16字节边界在ESP寄存器中的值。这导致堆栈对准的所有值。(??对齐原理? ?)

11行leave等于mov esp,ebppop ebp

GCC (AT&T):

1
2
3
4
5
6
7
8
9
10
11
12
.LC0:
.string "hello, world\n"
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call printf
movl $0, %eax
leave
ret

Intel与AT&T语法区别:

  1. 操作数位置相反

    In Intel-syntax:

    在操作数中添加”=”

    AT&T syntax: .

    在操作数中添加“→”

  1. 寄存器前加%,立即数前加$

  2. 操作后缀添加大小

    b — byte (8 bits)

    w — word (16 bits)

    l — long (32 bits)

    q — quad (64 bits)

  3. 地址描述方式AT&T采用(),Intel采用[],寻址方式也不同。

MSVC:X86-64

1
2
3
4
5
6
7
8
9
$SG2989 DB 'hello, world', 0AH, 00H
main PROC
sub rsp, 40
lea rcx, OFFSET FLAT:$SG2989//通过rcx寄存器传输指针
call printf
xor eax, eax
add rsp, 40
ret 0
main ENDP

In Win64, 4 function arguments are passed in the RCX , RDX , R8 , and R9 registers

GCC:X86-64

1
2
3
4
5
6
7
8
9
.string "hello, world\n"
main:
sub rsp, 8
mov edi, OFFSET FLAT:.LC0 ; "hello, world\n"
xor eax, eax ; number of vector registers passed
call printf
xor eax, eax
add rsp, 8
ret

The first 6 arguments are passed in the RDI , RSI , RDX , RCX , R8 , and R9 registers, and the rest—via the stack.

64-bit 模式下,写入低32bit寄存器,高32bits被清零。

Function prologue and epilogue

prologue:

1
2
3
push ebp
mov ebp, esp
sub esp, X

epilogue:

1
2
3
mov esp, ebp
pop ebp
ret 0

stack

主要理解push和pop,sp和bp

Save the function’s return address

Donate comment here